package middleware

import (
	"bytes"
	"encoding/json"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"svs/global"
	"svs/model"
	"svs/model/result"
	"svs/service"
	"svs/util"
	"time"
)

func OperationHandle() gin.HandlerFunc {
	return func(c *gin.Context) {
		zap.L().Info("operation middleware")

		path := c.Request.URL.Path
		method := c.Request.Method
		claims, err := util.GetClaims(c)
		var userId uint
		if err == nil {
			userId = claims.ID
		} else {
			userId = 0
		}

		var body []byte
		if method != http.MethodGet {
			body, _ = ioutil.ReadAll(c.Request.Body)
			c.Request.Body = ioutil.NopCloser(bytes.NewReader(body))
		} else {
			query := c.Request.URL.RawQuery
			query, _ = url.QueryUnescape(query)
			split := strings.Split(query, "&")
			m := make(map[string]string)
			for _, v := range split {
				kv := strings.Split(v, "=")
				if len(kv) == 2 {
					m[kv[0]] = kv[1]
				}
			}
			body, _ = json.Marshal(&m)
		}

		writer := responseBodyWriter{
			ResponseWriter: c.Writer,
			body:           &bytes.Buffer{},
		}

		c.Writer = writer

		c.Next()

		var apiRole string = "root"

		zap.L().Debug("记录日志的人员", zap.Any("role", apiRole))
		var retBody result.Response
		json.Unmarshal(writer.body.Bytes(), &retBody)

		log := model.Log{
			UserId:       userId,
			Path:         path,
			Method:       method,
			Ip:           c.Request.Header.Get("X-Forwarded-For"),
			Agent:        c.Request.Header.Get("User-Agent"),
			Status:       uint(retBody.Code),
			ResponseData: writer.body.String(),
			ApiName:      service.GetApiName(path, method, strings.TrimSpace(string(body))),
			CreateTime:   time.Now().Unix(),
			Role:         apiRole,
			Body:         string(body),
		}
		if !json.Valid(body) && len(body) > 0 {
			log.Body = "上传文件"
		}
		go func() {
			global.DB.Model(&model.Log{}).Create(&log)
		}()

	}
}

type responseBodyWriter struct {
	gin.ResponseWriter
	body *bytes.Buffer
}

func (r responseBodyWriter) Write(b []byte) (int, error) {
	r.body.Write(b)
	return r.ResponseWriter.Write(b)
}
